/*
 * Copyright (C) 2025 Tsingteng MicroSystem
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "nci_rf.h"
#include "nci_utils.h"
#include "nfc_log_api.h"
#include "nci_format.h"
#include "discover_int.h"
#include "nci_task.h"
#include "nci_proprietary.h"

/**
 * @brief NCI RF相关命令实现
 * @file nci_rf.c
 */

/**
 * @brief 发送RF_DISCOVER_MAP命令
 *
 * @param entries 需要设置的discover map entry的数组
 * @param count discover map entry的个数
 *
 * @return 发送成功返回NCI_STATUS_OK，否则返回错误码
*/
tNCI_STATUS nci_rf_discover_map(tNCI_RF_DISCOVER_MAP_ENTRY *entries, uint8_t count) {
    if (entries == NULL || count == 0) {
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    tNCI_BUF *cmd = alloc_nci_buf(NCI_RF_DISCOVER_MAP_CMD);
    if (cmd == NULL) {
        return NCI_STATUS_EXT_ALLOC_FAILED;
    }

    UINT8_TO_BUF(cmd, count);
    for(uint8_t i = 0; i < count; i++) {
        UINT8_TO_BUF(cmd, entries[i].protocol);
        UINT8_TO_BUF(cmd, entries[i].mode);
        UINT8_TO_BUF(cmd, entries[i].interface);
    }

    tNCI_STATUS ret = nci_tp_send_nci(cmd);

    free_nci_buf(cmd);
    return ret;
}

/**
 * @brief 发送RF_SET_LISTEN_MODE_ROUTING命令
 *
 * @param entries 路由表中的条目数组
 * @param count 路由表中的条目个数
 *
 * @return 发送成功返回NCI_STATUS_OK，否则返回错误码
*/
tNCI_STATUS nci_rf_set_listen_mode_routing(tNCI_RF_ROUTING_ENTRY *entries, uint8_t count, bool more) {
    NFCLOG_D("count = %d, more=%d", count, more);
    if (entries == NULL || count == 0) {
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    tNCI_BUF *cmd = alloc_nci_buf(NCI_RF_SET_LISTEN_MODE_ROUTING_CMD);
    if (cmd == NULL) {
        return NCI_STATUS_EXT_ALLOC_FAILED;
    }

    if (more) {
        UINT8_TO_BUF(cmd, NCI_ROUTING_FOLLOW_MESSAGES);
    } else {
        UINT8_TO_BUF(cmd, NCI_ROUTING_LAST_MESSAGE);
    }
    UINT8_TO_BUF(cmd, count);

    for (uint8_t j = 0; j < count; j++) {
        tNCI_RF_ROUTING_ENTRY *entry = &entries[j];
        UINT8_TO_BUF(cmd, entry->qualifier_type);
        UINT8_TO_BUF(cmd, entry->entry_len + 2);
        UINT8_TO_BUF(cmd, entry->nfcee_id);
        UINT8_TO_BUF(cmd, entry->power_state);
        uint8_t *entry_data = (uint8_t*) &entry->entry_data;
        ARRAY_TO_BUF(cmd, entry_data, entry->entry_len);
    }

    tNCI_STATUS ret = nci_tp_send_nci(cmd);

    free_nci_buf(cmd);
    return ret;
}

/**
 * @brief 发送RF_GET_LISTEN_MODE_ROUTING命令
 *
 * @param[out] entries 保存获取到的路由的数组
 * @param[out] count 返回获取到的路由条目数量
 *
 * @return 发送成功返回NCI_STATUS_OK，否则返回错误码
*/
tNCI_STATUS nci_rf_get_listen_mode_routing(tNCI_RF_ROUTING_ENTRY *entries, uint8_t *count) {
    if (entries == NULL || count == NULL) {
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    tNCI_BUF *cmd = alloc_nci_buf(NCI_RF_GET_LISTEN_MODE_ROUTING_CMD);
    tNCI_BUF *ntf = alloc_nci_buf(NCI_RF_GET_LISTEN_MODE_ROUTING_NTF);
    if (cmd == NULL || ntf == NULL) {
        free_nci_buf(cmd);
        free_nci_buf(ntf);
        return NCI_STATUS_EXT_ALLOC_FAILED;
    }

    tNCI_STATUS ret = nci_tp_send_nci_get_rsp_ntf(cmd, NULL, ntf, true, NCI_DEFAULT_WAIT_TIME);

    uint8_t *p;

    if (ret != NCI_STATUS_OK) {
        goto cleanup;
    }

    p = ntf->data;
    p++; // skip more flag TODO

    STREAM_TO_UINT8(*count, p);

    for (uint8_t i = 0; i < *count; i++) {
        tNCI_RF_ROUTING_ENTRY *entry = &entries[i];
        STREAM_TO_UINT8(entry->qualifier_type, p);
        STREAM_TO_UINT8(entry->entry_len, p);
        STREAM_TO_UINT8(entry->nfcee_id, p);
        STREAM_TO_UINT8(entry->power_state, p);
        entry->entry_len -= 2;
        uint8_t *entry_data = (uint8_t*) &entry->entry_data;
        STREAM_TO_ARRAY(entry_data, p, entry->entry_len);
    }

cleanup:
    free_nci_buf(cmd);
    free_nci_buf(ntf);
    return ret;
}

/**
 * @brief 发送RF_DISCOVER命令
 *
 * @param entries 发现模式列表中的条目数组
 * @param count 发现模式列表中的条目个数
 *
 * @return 发送成功返回NCI_STATUS_OK，否则返回错误码
*/
tNCI_STATUS nci_rf_discover(tNCI_RF_DISCOVER_ENTRY *entries, uint8_t count) {
    if (entries == NULL || count == 0) {
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    tNCI_BUF *cmd = alloc_nci_buf(NCI_RF_DISCOVER_CMD);
    if (cmd == NULL) {
        return NCI_STATUS_EXT_ALLOC_FAILED;
    }

    UINT8_TO_BUF(cmd, count);
    for (uint8_t i = 0; i < count; i++) {
        UINT8_TO_BUF(cmd, entries[i].tech_and_mode);
        UINT8_TO_BUF(cmd, entries[i].discovery_frequency);
    }

    tNCI_STATUS ret = nci_tp_send_nci(cmd);

    free_nci_buf(cmd);

    return ret;
}

/**
 * @brief 发送RF_DISCOVER_SELECT命令
 *
 * @param id 选择的卡片的Discovery ID
 * @param protocol 选择要激活的协议
 * @param interface 选择要激活的接口
 *
 * @return 发送成功返回NCI_STATUS_OK，否则返回错误码
*/
tNCI_STATUS nci_rf_discovery_select(tNCI_RF_DISCOVERY_ID id, tNCI_RF_PROTOCOL protocol, tNCI_RF_INTERFACE interface) {
    tNCI_BUF *cmd = alloc_nci_buf(NCI_RF_DISCOVER_SELECT_CMD);
    if (cmd == NULL) {
        return NCI_STATUS_EXT_ALLOC_FAILED;
    }

    UINT8_TO_BUF(cmd, id);
    UINT8_TO_BUF(cmd, protocol);
    UINT8_TO_BUF(cmd, interface);

    tNCI_STATUS ret = nci_tp_send_nci(cmd);

    free_nci_buf(cmd);
    return ret;
}

/**
 * @brief 发送RF_DISCOVER_SELECT命令并等待卡片激活
 *
 * @param[in] id 选择的卡片的Discovery ID
 * @param[in] protocol 选择要激活的协议
 * @param[in] interface 选择要激活的接口
 * @param[in] timeout 等待超时时间
 * @param[out] p_intf_param 保存激活的接口参数的指针，不能为NULL
 *
 * @return 发送成功返回NCI_STATUS_OK，否则返回错误码。如果p_intf_param为NULL，则不等待NTF，直接返回
 */
tNCI_STATUS nci_rf_select_wait_activated(tNCI_RF_DISCOVERY_ID id, tNCI_RF_PROTOCOL protocol, tNCI_RF_INTERFACE interface, uint32_t timeout, tNCI_RF_INTF_ACTIVATED_PARAMS *p_intf_param) {
    if (!p_intf_param) {
        NFCLOG_E("p_intf_param is NULL");
        return NCI_STATUS_EXT_INVALID_PARAM;
    }
    const uint8_t ntf_wait_list_size = 3;
    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;

    tNCI_BUF *cmd = alloc_nci_buf(NCI_RF_DISCOVER_SELECT_CMD);
    tNCI_BUF *ntf = alloc_nci_buf(NCI_RF_INTF_ACTIVATED_NTF);
    tNCI_WAIT_BUF *p_ntf_wait_list = osi_calloc(ntf_wait_list_size * sizeof(tNCI_WAIT_BUF));
    if (cmd == NULL || ntf == NULL || p_ntf_wait_list == NULL) {
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto cleanup;
    }

    UINT8_TO_BUF(cmd, id);
    UINT8_TO_BUF(cmd, protocol);
    UINT8_TO_BUF(cmd, interface);

    SET_WAIT_BUF(p_ntf_wait_list[0], NCI_RF_INTF_ACTIVATED_NTF, NCI_STATUS_OK, ntf);
    SET_WAIT_BUF(p_ntf_wait_list[1], NCI_CORE_GENERIC_ERROR_NTF, NCI_STATUS_DISCOVERY_TARGET_ACTIVATION_FAILED, NULL);
    SET_WAIT_BUF(p_ntf_wait_list[2], NCI_CORE_INTERFACE_ERROR_NTF, NCI_STATUS_RF_PROTOCOL_EXCEPTION, NULL);

    ret = nci_tp_send_nci_get_rsp_wait_ntf(cmd, NULL, timeout, false, p_ntf_wait_list, ntf_wait_list_size, nci_tp_default_ntf_wait_cback);

    if (ret != NCI_STATUS_OK) {
        goto cleanup;
    }

    if (p_intf_param) {
        ret = nci_fmt_intf_activation_ntf(ntf->data, ntf->len, p_intf_param);
    }

cleanup:
    free_nci_buf(cmd);
    free_nci_buf(ntf);
    if (p_ntf_wait_list) {
        osi_free(p_ntf_wait_list);
    }
    return ret;
}

/**
 * @brief 发送RF_DEACTIVATE命令
 *
 * @param type 去激活类型
 * @param wait_ntf 是否等待NTF
 *
 * @return 发送成功返回NCI_STATUS_OK，否则返回错误码
*/
tNCI_STATUS nci_rf_deactivate(tNCI_RF_DEACTIVATE_TYPE type, bool wait_ntf) {
    tNCI_BUF *cmd = alloc_nci_buf(NCI_RF_DEACTIVATE_CMD);
    if (cmd == NULL) {
        return NCI_STATUS_EXT_ALLOC_FAILED;
    }
    tNCI_BUF *ntf = NULL;


    UINT8_TO_BUF(cmd, type);

    tNCI_STATUS ret = NCI_STATUS_EXT_FAILED;

    if (wait_ntf) {
        ntf = alloc_nci_buf(NCI_RF_DEACTIVATE_NTF);
        if (ntf == NULL) {
            goto cleanup;
        }
    }

    ret = nci_tp_send_nci_get_rsp_ntf(cmd, NULL, ntf, wait_ntf, NCI_DEFAULT_WAIT_TIME);

    if (ret != NCI_STATUS_OK) {
        goto cleanup;
    }

cleanup:
    free_nci_buf(cmd);
    free_nci_buf(ntf);
    return ret;
}

/**
 * @brief 发送RF_T3T_POLLING命令
 *
 * @param[in] param 请求参数
 * @param[out] sensf_res_list 保存响应结果列表, 为NULL时表示不需要获取响应结果
 * @param[inout] res_count 返回的T3T识别码响应列表个数，为NULL时表示不需要获取响应结果, 传入时为最大返回个数，返回时为实际返回个数
 *
 * @return 发送成功返回NCI_STATUS_OK，否则返回错误码
*/
tNCI_STATUS nci_rf_t3t_polling(tNCI_RF_SENSF_REQ_PARAMS params, tNCI_RF_SENSF_RES *sensf_res_list, uint8_t *res_count) {
    tNCI_BUF *cmd = alloc_nci_buf(NCI_RF_T3T_POLLING_CMD);
    tNCI_BUF *ntf = alloc_nci_buf(NCI_RF_T3T_POLLING_NTF);
    tNCI_STATUS ret = NCI_STATUS_FAILED;
    if (cmd == NULL || ntf == NULL) {
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto cleanup;
    }

    UINT32_TO_BUF_BE(cmd, params);

    ret = nci_tp_send_nci_get_rsp_ntf(cmd, NULL, ntf, true, NCI_DEFAULT_WAIT_TIME);
    if (ret != NCI_STATUS_OK) {
        goto cleanup;
    }

    uint8_t *p = ntf->data;
    STREAM_TO_UINT8(ret, p);

    if (ret != NCI_STATUS_OK) {
        goto cleanup;
    }

    if (res_count == NULL || sensf_res_list == NULL) {
        // 忽略响应结果
        goto cleanup;
    }

    uint8_t res_cap = *res_count;
    STREAM_TO_UINT8(*res_count, p);
    uint8_t save_count = res_cap < *res_count ? res_cap : *res_count;
    for (uint8_t i = 0; i < save_count; i++) {
        tNCI_RF_SENSF_RES *res = &sensf_res_list[i];
        STREAM_TO_UINT8(res->length, p);
        STREAM_TO_ARRAY(res->res, p, res->length);
    }

cleanup:
    free_nci_buf(cmd);
    free_nci_buf(ntf);
    return ret;
}

/**
 * @brief 发送RF_ISO_DEP_NAK_PRESENCE命令
 *
 * @return 发送成功返回NCI_STATUS_OK，否则返回错误码
*/
tNCI_STATUS nci_rf_iso_dep_nak_presence() {
    tNCI_BUF *cmd = alloc_nci_buf(NCI_RF_ISO_DEP_NAK_PRESENCE_CMD);
    tNCI_BUF *ntf = alloc_nci_buf(NCI_RF_ISO_DEP_NAK_PRESENCE_NTF);
    tNCI_STATUS ret = NCI_STATUS_FAILED;
    if (cmd == NULL || ntf == NULL) {
        ret = NCI_STATUS_EXT_ALLOC_FAILED;
        goto cleanup;
    }

    ret = nci_tp_send_nci_get_rsp_ntf(cmd, NULL, ntf, true, NCI_DEFAULT_WAIT_TIME);
    if (ret != NCI_STATUS_OK) {
        goto cleanup;
    }

    uint8_t *p = ntf->data;
    STREAM_TO_UINT8(ret, p);

cleanup:
    free_nci_buf(cmd);
    free_nci_buf(ntf);
    return ret;
}

/**
 * @brief 处理6103 NTF
 */
static void nci_rf_discover_ntf(uint8_t *data, uint16_t data_len) {
    tNCI_RF_DISCOVER_PARAMS *params = osi_calloc(sizeof(tNCI_RF_DISCOVER_PARAMS));
    if (!params) {
        NFCLOG_E("Failed to allocate memory for nci_rf_discover_ntf");
        return;
    }
    tNCI_STATUS ret = nci_fmt_discover_ntf(data, data_len, params);
    if (ret != NCI_STATUS_OK) {
        goto cleanup;
    }
    ret = on_rf_discovered(params);
cleanup:
    if (ret != NCI_STATUS_EXT_NOT_FREE) { // 返回NCI_STATUS_EXT_NOT_FREE，表示params不需要free
        osi_free(params);
    }
}
/**
 * @brief 处理6105 NTF
 */
static void nci_rf_intf_activated_ntf(uint8_t *data, uint16_t data_len) {
    tNCI_RF_INTF_ACTIVATED_PARAMS *params = osi_calloc(sizeof(tNCI_RF_INTF_ACTIVATED_PARAMS));
    if (!params) {
        NFCLOG_E("Failed to allocate memory for nci_rf_intf_activated_ntf");
        return;
    }
    tNCI_STATUS ret = nci_fmt_intf_activation_ntf(data, data_len, params);
    if (ret != NCI_STATUS_OK) {
        goto cleanup;
    }
    ret = on_rf_intf_activated(params);
cleanup:
    if (ret != NCI_STATUS_EXT_NOT_FREE) { // 返回NCI_STATUS_EXT_NOT_FREE，表示params不需要free
        osi_free(params);
    }
}
/**
 * @brief 处理6106 NTF
 */
static void nci_rf_deactivate_ntf(uint8_t *data, uint16_t data_len) {
    (void) data_len;
    tNCI_RF_DEACTIVATE_TYPE type;
    tNCI_RF_DEACTIVATE_REASON reason;

    STREAM_TO_UINT8(type, data);
    STREAM_TO_UINT8(reason, data);

    on_rf_deactivated(type, reason);
}
/**
 * @brief 处理6107 NTF
 */
static void nci_rf_field_info_ntf(uint8_t *data, uint16_t data_len) {
    OSI_CHK_PARAM_INVALID(data_len != 1, return);
    OSI_CHK_PARAM_INVALID(!data, return);
    uint8_t field_info = data[0];
    nci_task_post(NCI_TASK_EVT_CE_FIELD_INFO, field_info, 0, NULL);
}
#if IS_FEATURE_ON(NCI_FEATURE_VS)
/**
 * @brief 处理6109 NTF
 */
static void nci_rf_nfcee_action_ntf(uint8_t *data, uint16_t data_len) {
    OSI_CHK_PARAM_INVALID(data_len == 0, return);
    OSI_CHK_PARAM_INVALID(!data, return);
    nci_ee_action_ntf_handle(data, data_len);
}
#endif /* IS_FEATURE_ON(NCI_FEATURE_VS) */
static void nci_rf_nfcee_discovery_req_ntf(uint8_t *data, uint16_t data_len) {
    if (data_len == 1) {
        NFCLOG_W("no ee discovery req entry.");
        return;
    }
    uint8_t entry_num = data[0];
    uint8_t entry_len = data_len - 1;
    // 如果数据不满足entry的长度，则不处理
    /* 5 = type(1) + len(1) + value(3)*/
    if (entry_len < (5 * entry_num)) {
        NFCLOG_W("invalid EE_DISCOVERY_REQ format");
        return;
    }
    uint8_t* entry = osi_calloc(entry_len);
    if (!entry) {
        NFCLOG_W("calloc failed");
        return;
    }
    osi_memcpy_s(entry, entry_len, &data[1], entry_len);
    // entry的内存在post成功后会由注册事件方的cleanup函数释放，但失败时需要由post事件处释放
    if (nci_task_post(NCI_TASK_EVT_EE_DISCOVERY_REQ_NTF, entry_num, entry_len, entry) != NCI_STATUS_OK) {
        osi_free(entry);
    }
}

/**
 * @brief 处理RF相关的NTF
 *
 * @param oid NTF的Operation ID
 * @param data NTF的payload数据，不包含NCI头
 * @param data_len NTF的payload数据长度
 */
void nci_rf_ntf_handle(uint8_t oid, uint8_t *data, uint16_t data_len) {
    if (data == NULL || data_len == 0) {
        NFCLOG_W("Invalid data 0x%p, len %d", data, data_len);
        return;
    }
    switch (oid) {
        case NCI_RF_DISCOVER:
            nci_rf_discover_ntf(data, data_len);
            break;
        case NCI_RF_INTF_ACTIVATED:
            nci_rf_intf_activated_ntf(data, data_len);
            break;
        case NCI_RF_DEACTIVATE:
            nci_rf_deactivate_ntf(data, data_len);
            break;
        case NCI_RF_FIELD_INFO:
            nci_rf_field_info_ntf(data, data_len);
            break;
        case NCI_RF_NFCEE_ACTION:
#if IS_FEATURE_ON(NCI_FEATURE_VS)
            nci_rf_nfcee_action_ntf(data, data_len);
#endif /* IS_FEATURE_ON(NCI_FEATURE_VS) */
            break;
        case NCI_RF_NFCEE_DISCOVERY_REQ:
            nci_rf_nfcee_discovery_req_ntf(data, data_len);
            break;
        default:
            NFCLOG_W("Unknown NCI_RF_NTF oid: 0x%02X", oid);
            break;
    }
}
